module alu(
  input                          clk           ,
  input                          reset         ,
  input                          alu_can_ov    ,
  input  [15:0] alu_op,
  input  [63:0] alu_src1,
  input  [63:0] alu_src2,
  output [63:0] alu_result,

  output        alu_stall                ,
  output        alu_ex
);

wire op_add;   //�ӷ�����
wire op_sub;   //��������
wire op_slt;   //�з��űȽϣ�С����λ
wire op_sltu;  //�޷��űȽϣ�С����λ
wire op_and;   //��λ��
wire op_nor;   //��λ���
wire op_or;    //��λ��
wire op_xor;   //��λ���
wire op_sll;   //�߼�����
wire op_srl;   //�߼�����
wire op_sra;   //��������
wire op_lui;   //���������ڸ߰벿��
wire op_rv32i;

wire src1_sign;
wire src2_sign;
wire adder_result_sign;

// control code decomposition
assign op_add  = alu_op[ 0];
assign op_sub  = alu_op[ 1];
assign op_slt  = alu_op[ 2];
assign op_sltu = alu_op[ 3];
assign op_and  = alu_op[ 4];
assign op_nor  = alu_op[ 5];
assign op_or   = alu_op[ 6];
assign op_xor  = alu_op[ 7];
assign op_sll  = alu_op[ 8];
assign op_srl  = alu_op[ 9];
assign op_sra  = alu_op[10];
assign op_lui  = alu_op[11];
assign op_rv32i= alu_op[12];


wire [63:0] add_sub_result;
wire [63:0] slt_result; 
wire [63:0] sltu_result;
wire [63:0] and_result;
wire [63:0] nor_result;
wire [63:0] or_result;
wire [63:0] xor_result;
wire [63:0] lui_result;
wire [63:0] sll_result;
wire [127:0] sr64_result; 
wire [63:0] sr_result; 
//
wire [63:0] add_sub_result_w; 
wire [63:0] sllw_result; 
// wire [63:0] addw_r


// 64-bit adder
wire [63:0] adder_a;
wire [63:0] adder_b;
wire        adder_cin;
wire [63:0] adder_result;
wire        adder_cout;

assign adder_a   = alu_src1;
assign adder_b   = (op_sub | op_slt | op_sltu) ? ~alu_src2 : alu_src2;
assign adder_cin = (op_sub | op_slt | op_sltu) ? 1'b1      : 1'b0;
assign {adder_cout, adder_result} = adder_a + adder_b + adder_cin;

// ADD, SUB result
assign add_sub_result_w = {{32{adder_result[31]}}, adder_result[31:0]};
assign add_sub_result = op_rv32i  ? add_sub_result_w : adder_result;


assign src1_sign = alu_src1[63] ;
assign src2_sign = alu_src2[63]; 
assign adder_result_sign = adder_result[63];

assign alu_ex   = 1'b0;
//  op_add && alu_can_ov && (src1_sign == src2_sign  && adder_result_sign != src1_sign)
//               ||  op_sub && alu_can_ov && (src1_sign != src2_sign  && adder_result_sign == src2_sign );
// SLT result
assign slt_result[63:1] = 63'b0;
assign slt_result[0]    = (alu_src1[63] & ~alu_src2[63])
                        | ((alu_src1[63] ~^ alu_src2[63]) & adder_result[63]);

// SLTU result
assign sltu_result[63:1] = 63'b0;
assign sltu_result[0]    = ~adder_cout;

// bitwise operation
assign and_result = alu_src1 & alu_src2;
assign or_result  = alu_src1 | alu_src2 ;
assign nor_result = ~or_result;
assign xor_result = alu_src1 ^ alu_src2;
assign lui_result = {{32{alu_src2[31]}}, alu_src2[31:0]};
//


// SLL result
wire [5:0] sll_src;
wire [63:0] slld_result;
assign sll_src   = op_rv32i ? {1'b0,alu_src2[4:0]} : alu_src2[5:0];
assign slld_result = alu_src1 << sll_src;
assign sllw_result = {{32{slld_result[31]}},slld_result[31:0]};
assign sll_result  = op_rv32i ? sllw_result : slld_result;
// SRL, SRA result
wire [5:0] sr_src2;
assign sr_src2 = op_rv32i ? {1'b0,alu_src2[4:0]} : alu_src2[5:0];
wire [127:0] sr_src1;
assign sr_src1 = op_rv32i ? {{96{op_sra & op_rv32i & alu_src1[31]}},alu_src1[31:0] } : 
                             {{64{op_sra & alu_src1[63]}}, alu_src1[63:0]};
assign sr64_result = sr_src1 >> sr_src2;

assign sr_result   = sr64_result[63:0];
assign alu_stall = 1'b0;

assign alu_result = ({64{op_add|op_sub}} & add_sub_result)
                  | ({64{op_slt       }} & slt_result)
                  | ({64{op_sltu      }} & sltu_result)
                  | ({64{op_and       }} & and_result)
                  | ({64{op_nor       }} & nor_result)
                  | ({64{op_or        }} & or_result)
                  | ({64{op_xor       }} & xor_result)
                  | ({64{op_lui       }} & lui_result)
                  | ({64{op_sll       }} & sll_result)
                  | ({64{op_srl|op_sra}} & sr_result);


endmodule
